﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using System.Windows.Threading;

namespace LS.DicomViewer.Common
{
    public class UICommand : ICommand
    {
        public event EventHandler? CanExecuteChanged;

        Func<object, bool> canExecute { get; set; }

        Action execute;

        public bool CanExecute(object? parameter)
        {
            if (canExecute == null) return true;
            return canExecute.Invoke(parameter);
        }

        public void Execute(object? parameter)
        {
            execute?.Invoke();
        }

        public UICommand() { }

        public UICommand(Action execute, Func<object, bool> canExecute = null)
        {
            this.canExecute = canExecute;
            this.execute = execute;
        }

        public void NotifyCanExecuteChanged() => CanExecuteChanged?.Invoke(this, new EventArgs());
    }

    public abstract class BindableObject<T> : INotifyPropertyChanged, INotifyPropertyChanging
    {
        public Dispatcher Dispatcher { get; set; } = System.Windows.Application.Current.Dispatcher;

        bool isBusy = false;

        public bool IsBusy { get => isBusy; set => SetProperty(ref isBusy, value); }

        public event PropertyChangedEventHandler PropertyChanged;

        public event PropertyChangingEventHandler PropertyChanging;

        public virtual void OnPropertyChanging(string propertyName, object oldValue, object newValue)
        {
            NotifyPropertyChanging(propertyName);
        }

        public virtual void OnPropertyChanged(string propertyName, object oldValue, object newValue)
        {
            NotifyPropertyChanged(propertyName);
        }

        protected internal void NotifyPropertyChanging(string propertyName)
        {
            this.PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
        }

        protected internal void NotifyPropertyChanged(string propertyName)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected virtual void SetProperty<P>(ref P field, P value, [CallerMemberName] string propertyName = "")
        {
            if (!EqualityComparer<P>.Default.Equals(field, value))
            {
                P val = field;
                this.PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
                OnPropertyChanging(propertyName, val, value);

                field = value;
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                OnPropertyChanged(propertyName, val, value);
            }
        }
    }
}
